home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
FM Towns: Free Software Collection 10
/
FM Towns Free Software Collection 10.iso
/
ms_dos
/
lib
/
happyps3
/
calc.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
1995-02-07
|
9KB
|
256 lines
(*********************************************************************
* *** 電卓 *** *
* *
* HAPPyのサンプルプログラム *
* (作者 浅野比富美 Public Domain Software) *
*********************************************************************)
program calculator(input,output) ;
label 1 ;
const SYNe = '式が誤っている ' ;
DIVe = '0で割ろうとしている ' ;
LimitInt = 99999999 ; { 整数演算の最大値 }
type kindType = (int,rea) ; { 整数 実数 }
valueType = record { 演算結果 の 型 }
kind : kindType ; { 結果の型 }
vi : integer ; { 整数の値 }
vr : real { 実数の値 }
end ;
string20 = packed array[1..20] of char ; { エラーメッセージの型 }
var ch : char ; { 読んだ文字 }
val,oldVal : valueType ; { 演算結果 }
(****************************)
(* エラーメッセージ出力処理 *)
(****************************)
procedure error(message : string20) ;
begin
writeln(message) ;
readln ; { 以降改行までの入力を無視する }
goto 1 { 次の式の処理(メイン処理)へ }
end ;
(****************************)
(* 実数変換処理 *)
(****************************)
procedure cnvFloat(var val : valueType; r : real) ;
begin
val.kind := rea ;
val.vr := r
end ;
(****************************)
(* 数の入力処理 *)
(****************************)
procedure inputNumber(var val : valueType) ;
label 8 ;
var p : real ;
sign : char ;
begin
with val do
begin
kind := int ; { とりあえず整数としておく }
vi := 0 ;
if (ch = '+') or (ch ='-') then { 符号がある時 }
begin
sign := ch ; { 符号を記憶しておく }
read(ch)
end
else sign := ' ' ;
if (ch = 'x') or (ch = 'X') then { 前回の答え数値の指示の時 }
begin
val := oldVal ; { 前回の答えを 値 とする }
read(ch) ;
goto 8 { 符号の処理へ }
end ;
if ('0' <= ch) and (ch <= '9') then
begin
vi := ord(ch) - ord('0') ;
read(ch) ;
while ('0' <= ch) and (ch <= '9') do
begin
if kind = int then
begin
vi := 10 * vi + (ord(ch)-ord('0')) ;
if vi > LimitInt then { 整数オーバーフローしている時 }
cnvFloat(val,vi) { 以降の演算は実数で行う }
end
else vr := 10 * vr + (ord(ch)-ord('0')) ;
read(ch)
end ;
if ch = '.' then { 小数点がある時 }
begin
cnvFloat(val,vi) ; { 以降の演算は実数で行う }
p := 0.1 ;
read(ch) ;
if ('0' <= ch) and (ch <= '9') then
repeat
vr := vr + p * (ord(ch)-ord('0')) ;
p := 0.1 * p ;
read(ch)
until ('0' > ch) or (ch > '9')
else error(SYNe)
end
end
else error(SYNe) ;
8: if sign = '-' then { 負の符号の時 }
if kind = int then vi := -vi { 値を反転する }
else vr := -vr
end {with val}
end ;
(******************************)
(* オーバーフローチェック処理 *
(******************************)
procedure checkOverflow(var val : valueType ; rr : real; ii : integer) ;
begin
if abs(rr) > LimitInt then cnvFloat(val,rr) { 整数演算限界 ・・・>実数演算 }
else val.vi := ii
end ;
(*****************************)
(* 加算処理 *)
(*****************************)
procedure add(var val1 : valueType; val2 : valueType) ;
begin
if val1.kind = int then
if val2.kind = int then
checkOverflow(val1, val1.vi+val2.vi, val1.vi+val2.vi)
else cnvFloat(val1, val1.vi+val2.vr)
else
if val2.kind = int then val1.vr := val1.vr + val2.vi
else val1.vr := val1.vr + val2.vr
end ;
(*****************************)
(* 減算処理 *)
(*****************************)
procedure sub(var val1 : valueType; val2 : valueType) ;
begin
if val1.kind = int then
if val2.kind = int then
checkOverflow(val1, val1.vi-val2.vi, val1.vi-val2.vi)
else cnvFloat(val1, val1.vi-val2.vr)
else
if val2.kind = int then val1.vr := val1.vr - val2.vi
else val1.vr := val1.vr - val2.vr
end ;
(*****************************)
(* 乗算処理 *)
(*****************************)
procedure mul(var val1 : valueType; val2 : valueType) ;
begin
if val1.kind = int then
if val2.kind = int then
checkOverflow(val1, val1.vi*val2.vi, val1.vi*val2.vi)
else cnvFloat(val1, val1.vi*val2.vr)
else
if val2.kind = int then val1.vr := val1.vr * val2.vi
else val1.vr := val1.vr * val2.vr
end ;
(****************************)
(* 式の処理 *)
(****************************)
procedure expression(var val : valueType) ;
var eVal : valueType ;
(**************************)
(* 項の処理 *)
(**************************)
procedure term(var Val : valueType) ;
var tVal : valueType ;
(***********************)
(* 因子の処理 *)
(***********************)
procedure factor(var val : valueType) ;
begin
if ch = '(' then { 括弧記法の時 }
begin { ( 式 ) の 処理を行う }
read(ch) ;
expression(val) ;
if ch = ')' then read(ch)
else error(SYNe) { 式の誤り }
end
else inputNumber(val)
end {factor} ;
begin { term }
factor(val) ;
while (ch = '*') or (ch = '/') do
if ch = '*' then
begin
read(ch) ;
factor(tVal) ;
mul(val,tval) { val := val * tVal }
end
else { ch = '/' }
begin
read(ch) ;
factor(tVal) ;
if ((tVal.kind = int) and (tVal.vi = 0)) or { 0 除算チェック }
(tVal.kind = rea) and (tVal.vr = 0.0) then error(DIVe) ;
if val.kind = int then
if tVal.kind = int then cnvFloat(val, val.vi / tVal.vi)
else cnvFloat(val, val.vi / tVal.vr)
else
if tVal.kind = int then val.vr := val.vr / tVal.vi
else val.vr := val.vr / tVal.vr
end
end {term} ;
begin { expression }
term(val) ;
while (ch = '+') or (ch = '-') do
if ch = '+' then
begin
read(ch) ;
term(eVal) ;
add(val,eVal) { val := val + eVval }
end
else { ch = '-' }
begin
read(ch) ;
term(eVal) ;
sub(val,eval) { val := val - eVval }
end
end {expression} ;
(****************************)
(* 開始処理 *)
(****************************)
procedure start ;
begin
write('# ') ; { プロンプト出力 }
read(ch) { 最初の文字を読み込む }
end ;
(****************************)
(* メイン処理 *)
(****************************)
begin
1:
start ;
while (ch <> 'q') and (ch <> 'Q') do { q または Q で 電卓終了 }
begin
expression(val) ;
if ch <> '=' then writeln('式の最後は''=''で終わってね.') ;
if val.kind = int then writeln(val.vi)
else writeln(val.vr) ;
readln ; { 以降改行までの入力を無視する }
oldVal := val ; { 変数x のために 今の値を退避 }
start
end
end.